package com.luoboduner.moo.tool.util.vm;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Expression;
import lombok.Getter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * JavaParser
 * 将java 解析位对应的结构
 */
public class JavaParser {

  // 领域模型----------------------------------------------------------------
  @Getter
  public static class ClassInfo {
    public String name;
    public String javaDoc;
    public List<AnnotationInfo> annotations = new ArrayList<>();
    public List<FieldInfo> fields = new ArrayList<>();
    public List<MethodInfo> methods = new ArrayList<>();
  }

  @Getter
  public static class MethodInfo {
    public String name;
    public String javaDoc;
    public List<ParamInfo> args = new ArrayList<>();
    public String returnType;
    public List<AnnotationInfo> annotations = new ArrayList<>();
  }
  @Getter
  public static class FieldInfo {
    public String name;
    public String type;
    public String javaDoc;
    public List<AnnotationInfo> annotations = new ArrayList<>();
  }
  @Getter
  public static class ParamInfo {
    public String name;
    public String type;
  }
  @Getter
  public static class AnnotationInfo {
    public String name;
    public Map<String, Object> values = new HashMap<>();
  }

  // 解析主方法--------------------------------------------------------------
  public static ClassInfo parseController(String javaCode) {
    CompilationUnit cu = new com.github.javaparser.JavaParser()
        .parse(javaCode)
        .getResult()
        .orElseThrow(() -> new RuntimeException("解析失败"));

    ClassInfo classInfo = new ClassInfo();

    cu.findAll(ClassOrInterfaceDeclaration.class).stream()
        .filter(c -> !c.isInterface()) // 过滤掉接口，只保留类
        .findFirst()
        .ifPresent(cd -> {
          // 类基本信息
          classInfo.name = cd.getNameAsString();
          cd.getJavadocComment().ifPresent(comment ->
              classInfo.javaDoc = parseJavadoc(comment));

          // 类注解
          classInfo.annotations = parseAnnotations(cd.getAnnotations());

          // 类字段（调整后的多字段处理）
          classInfo.fields = cd.getFields().stream()
              .map(JavaParser::parseField)
              .collect(Collectors.toList());

          // 类方法
          classInfo.methods = cd.getMethods().stream()
              .map(JavaParser::parseMethod)
              .collect(Collectors.toList());
        });
    return classInfo;
  }

  // 字段解析--------------------------------------------------------------
  private static FieldInfo parseField(FieldDeclaration field) {
    FieldInfo info = new FieldInfo();

    // 字段基本信息
    info.type = field.getElementType().asString();
    field.getJavadocComment().ifPresent(comment ->
        info.javaDoc = parseJavadoc(comment));
    //一个字段声明可能包含多个变量​（即通过逗号分隔的多个变量声明），这里已最后一个为准
    field.getVariables().forEach(v -> {
      info.name = v.getNameAsString();
    });

    // 字段注解
    info.annotations = parseAnnotations(field.getAnnotations());

    return info;
  }

  // 方法解析--------------------------------------------------------------
  private static MethodInfo parseMethod(MethodDeclaration method) {
    MethodInfo info = new MethodInfo();

    // 方法基本信息
    info.name = method.getNameAsString();
    method.getJavadocComment().ifPresent(comment ->
        info.javaDoc = parseJavadoc(comment));

    // 方法参数
    info.args = method.getParameters().stream()
        .map(p -> {
          ParamInfo param = new ParamInfo();
          param.name = p.getNameAsString();
          param.type = p.getType().asString();
          return param;
        })
        .collect(Collectors.toList());

    // 返回类型
    info.returnType = method.getType().asString();

    // 方法注解
    info.annotations = parseAnnotations(method.getAnnotations());

    return info;
  }

  // 通用注解解析----------------------------------------------------------
  private static List<AnnotationInfo> parseAnnotations(List<AnnotationExpr> annotations) {
    return annotations.stream().map(ann -> {
      AnnotationInfo info = new AnnotationInfo();
      info.name = ann.getNameAsString();

      if (ann.isNormalAnnotationExpr()) {
        ann.asNormalAnnotationExpr().getPairs().forEach(pair ->
            info.values.put(pair.getNameAsString(), parseValue(pair.getValue())));
      } else if (ann.isSingleMemberAnnotationExpr()) {
        info.values.put("value",
            parseValue(ann.asSingleMemberAnnotationExpr().getMemberValue()));
      }

      return info;
    }).collect(Collectors.toList());
  }

  // 值解析器--------------------------------------------------------------
  private static Object parseValue(Expression expr) {
    // 处理各种类型的值
    if (expr.isStringLiteralExpr()) return expr.asStringLiteralExpr().asString();
    if (expr.isArrayInitializerExpr()) return expr.asArrayInitializerExpr().getValues()
        .stream().map(JavaParser::parseValue).collect(Collectors.toList());
    if (expr.isAnnotationExpr()) return parseAnnotationExpr(expr.asAnnotationExpr());
    return expr.toString();  // 数字、布尔等基本类型
  }

  private static AnnotationInfo parseAnnotationExpr(AnnotationExpr expr) {
    AnnotationInfo info = new AnnotationInfo();
    info.name = expr.getNameAsString();

    if (expr.isNormalAnnotationExpr()) {
      expr.asNormalAnnotationExpr().getPairs().forEach(pair ->
          info.values.put(pair.getNameAsString(), parseValue(pair.getValue())));
    }
    return info;
  }

  // Javadoc解析-----------------------------------------------------------
  private static String parseJavadoc(JavadocComment comment) {
    return comment.getContent()
        .replaceAll("\\*", "")  // 去除注释符号
        .trim();
  }

  // 使用示例--------------------------------------------------------------
  public static void main(String[] args) {
    String code = "@RestController(\"path\")\n" +
        "public class UserController {\n" +
        "    /** 用户ID */\n" +
        "    @Autowired\n" +
        "    private UserService service;\n\n" +
        "    /**\n" +
        "     * 获取用户信息\n" +
        "     * @param id 用户ID\n" +
        "     */\n" +
        "    @GetMapping(\"/user/{id}\")\n" +
        "    public User getUser(@PathVariable Long id) {\n" +
        "        return service.findUser(id);\n" +
        "    }\n" +
        "}";

    ClassInfo classInfo = parseController(code);

    // 打印类信息
    System.out.println("类名称: " + classInfo.name);
    System.out.println("类注释: " + classInfo.javaDoc);
    System.out.println("类注解: " + classInfo.annotations.stream()
        .map(a -> "@" + a.name).collect(Collectors.joining(", ")));

    // 打印字段信息
    System.out.println("\n字段列表:");
    classInfo.fields.forEach(f -> {
      System.out.println(f.type + " " + f.name + " - " + f.javaDoc);
      System.out.println("  注解: " + f.annotations.stream()
          .map(a -> "@" + a.name).collect(Collectors.joining(", ")));
    });

    // 打印方法信息
    System.out.println("\n方法列表:");
    classInfo.methods.forEach(m -> {
      System.out.println(m.returnType + " " + m.name + "() - " + m.javaDoc);
      System.out.println("  参数: " + m.args.stream()
          .map(p -> p.type + " " + p.name).collect(Collectors.joining(", ")));
      System.out.println("  注解: " + m.annotations.stream()
          .map(a -> "@" + a.name).collect(Collectors.joining(", ")));
    });
  }
}
